package com.imu.purse.task;

import com.alibaba.fastjson.JSON;
import com.imu.constant.Constant;
import com.imu.purse.bean.CoreMoneyAddr;
import com.imu.purse.modules.base.entity.DictInfo;
import com.imu.purse.modules.base.service.DictInfoService;
import com.imu.purse.modules.bitcoin.BitcoinApi;
import com.imu.purse.modules.sms.SMSAliMessage;
import com.imu.purse.modules.sms.SendSMS;
import com.imu.purse.modules.trade.entity.ScheduleLogEntity;
import com.imu.purse.modules.trade.service.ScheduleLogService;
import com.imu.purse.mq.bean.TransBean;
import com.imu.purse.mq.produce.BitcoinProduce;
import com.qiniu.util.StringUtils;
import com.xiaoleilu.hutool.log.Log;
import com.xiaoleilu.hutool.log.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Component
public class BitcoinRun{
    private static final Log log = LogFactory.get(BitcoinRun.class);
    @Autowired
    private BitcoinApi bitcoinApi;


    @Autowired
    private ScheduleLogService scheduleLogService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private DictInfoService dictInfoService;

    @Autowired
    private SendSMS sms;

    @Autowired
    private BitcoinProduce bitcoinProduce;

    @Autowired
    private SMSAliMessage smsAliMessage;

    public void handleData(String coreStr){
        CoreMoneyAddr coreMoneyAddr = JSON.parseObject(coreStr,CoreMoneyAddr.class);
        //获取电子钱包的信息
        Map<String,Object> iMap = bitcoinApi.getInfo(coreStr);
        if(CollectionUtils.isEmpty(iMap) || iMap.get("error") != null
                || iMap.get("version") == null
                || StringUtils.isNullOrEmpty(iMap.get("version").toString())){
            log.info("获取电子钱包信息失败");
            //推送短信
            sendNotify();
            return;
        }
        String scheduleName = Constant.BITCOIN_SCHEDULE_NAME + "-" + (coreMoneyAddr.getUrl()+":"+coreMoneyAddr.getPort()).hashCode();
        //从数据字典中获取已处理的高度
        Integer bHeight = 0;
        try{
            //从缓存中获取最后一次更新的高度
            String rHeight = redisTemplate.opsForValue().get(Constant.BITCOIN_HEIGHT + "-" + (coreMoneyAddr.getUrl()+":"+coreMoneyAddr.getPort()).hashCode());
            if(!StringUtils.isNullOrEmpty(rHeight)){//缓存中有数据
                bHeight = Integer.valueOf(rHeight);
            }else{
                //缓存中没有数据从数据库获取
                bHeight = scheduleLogService.findMaxByNameAndType(scheduleName, Constant.ScheduleStatus.SUCCESS);
            }

        }catch(Exception e){
            log.error(e);
            //从数据库获取最后一次已处理的高度
            bHeight = scheduleLogService.findMaxByNameAndType(scheduleName, Constant.ScheduleStatus.SUCCESS);
        }
        bHeight = bHeight == null ? 0 : bHeight;

        int startHeight = bHeight;
        Timestamp startTime = new Timestamp(System.currentTimeMillis());
        //获取区块高度
        Integer bCount = bitcoinApi.getblockcount(coreStr);
        if(bCount == null){
            log.info("获取区块高度失败");
            //推送短信
            sendNotify();
            return;
        }

        if(bCount == 0){
            log.info("当前获取区块高度为0");
            return;
        }


        Map<String,Integer> resultMap = new HashMap<>(1);
        resultMap.put("status", 1);//默认成功
        while(bHeight <= bCount - 1){
            if(resultMap.get("status") == 0){
                log.info("钱包连接异常.......................");
                break;
            }
            //根据区块高度获取
            String blockHash = bitcoinApi.getblockhash(bHeight,coreStr);
            //log.info("当前高度::::::::::::::" + bHeight);
            bHeight++;
            if(StringUtils.isNullOrEmpty(blockHash) || blockHash.equals(Constant.MONEY_PACKAGE_CONNECT_OTHER_ERROR)){
                continue;
            }

            if(Constant.MONEY_PACKAGE_CONNECT_ERROR.equals(blockHash)){//如果钱包连接失败，则认为本次调用失败
                resultMap.put("status", 0);
                break;
            }
            //获取区块信息
            iMap = bitcoinApi.getblock(blockHash,coreStr);
            if(CollectionUtils.isEmpty(iMap) || (iMap.get("error") != null && iMap.get("error").toString().equals(Constant.MONEY_PACKAGE_CONNECT_OTHER_ERROR))
                    || iMap.get("height") == null || "0".equals(iMap.get("height").toString())){
                continue;
            }
            if(iMap.get("error") != null && Constant.MONEY_PACKAGE_CONNECT_ERROR.equals(iMap.get("error").toString())){//钱包连接异常
                resultMap.put("status", 0);
                break;
            }
            //获取当前块的时间
            Long bTime = Long.valueOf(iMap.get("time").toString());
            Object obj = iMap.get("tx");
            if(obj != null){
                List<String> tList = (List<String>)obj;
                handleData(tList,bTime,coreMoneyAddr);
            }
        }

        if(resultMap.get("status") == 0){
            //推送短信
            sendNotify();
            //发送短信
            return;
        }
        Timestamp endTime = new Timestamp(System.currentTimeMillis());
        //将本次的高度保存到缓存中
        redisTemplate.opsForValue().set(Constant.BITCOIN_HEIGHT + "-" + (coreMoneyAddr.getUrl() + ":" + coreMoneyAddr.getPort()).hashCode(),bCount+"");
        //保存数据
        saveScheduleData(scheduleName,resultMap,startHeight,bCount,startTime,endTime);
    }

    /**
     * 将交易ID推送到消息队列中
     * @param tList
     * @param blockTime
     * @param moneyAddr
     */
    private void handleData(List<String> tList,Long blockTime,CoreMoneyAddr moneyAddr){
        if(CollectionUtils.isEmpty(tList)){
            return;
        }
        for(String tId : tList){
            TransBean bean = new TransBean();
            bean.setDataType(0);
            bean.setTransId(tId);
            bean.setTransTime(blockTime);
            bean.setCoreMoneyAddr(JSON.toJSONString(moneyAddr));
            bitcoinProduce.sendData(bean);
            bean = null;
        }
    }

    /**
     * 保存定时任务记录
     * @param scheduleName
     * @param resultMap
     * @param startHeight
     * @param endHeight
     * @param startTime
     * @param endTime
     */
    private void saveScheduleData(String scheduleName,Map<String,Integer> resultMap,
                                  Integer startHeight,Integer endHeight,Timestamp startTime,
                                  Timestamp endTime){
        ScheduleLogEntity entity = new ScheduleLogEntity();
        entity.setScheduleName(scheduleName);
        entity.setStatus(resultMap.get("status"));
        entity.setStartHeight(startHeight);
        entity.setEndHeight(endHeight);
        entity.setStartTime(startTime);
        entity.setEndTime(endTime);
        entity.setTimeCreate(new Date());
        scheduleLogService.save(entity);
    }

    /**
     * 发送异常提醒
     */
    private void sendNotify(){
        List<DictInfo> dictList = dictInfoService.findCahceByCode("BITCOIN_NOTIFY");
        if(CollectionUtils.isEmpty(dictList)){
            return;
        }
        for(DictInfo info : dictList){
            if("phone".equals(info.getLabel())){
                if(!StringUtils.isNullOrEmpty(info.getValue())){
                    String [] phones = info.getValue().split(",");
                    smsAliMessage.sendRemind("5", phones);
                }
            }
        }
    }

    public static void main(String[] args){
        System.out.println(Constant.YTFCOIN_HEIGHT + "-" + ("http://47.75.158.31" + ":" + "8545").hashCode());
    }
}
